#include "ProcessManager.h"
#include "GameObject.h"
#include <assert.h>


using namespace Boon;


#define CID_TestComponent 1
typedef unsigned int uint;
uint callsCreate = 0;
uint callsStart = 0;
uint callsEnable = 0;
uint callsDisable = 0;
uint callsUpdate = 0;
uint callsDestroy = 0;
uint callsLate = 0;

class TestComponent : public GameComponent
{
	GAMECOMPONENT( TestComponent, GameComponent )

	virtual void OnCreate() { ++callsCreate; }
	virtual void OnEnable() { ++callsEnable; }
	virtual void OnStart() { ++callsStart; }
	virtual void Update() { ++callsUpdate; }
	virtual void OnDisable() { ++callsDisable; }
	virtual void OnDestroy() { ++callsDestroy; }
	virtual void LateUpdate() { ++callsLate; }
};

void ResetCounter()
{
	callsCreate = callsEnable = callsStart = callsUpdate = callsDisable = callsDestroy = callsLate = 0;
}

void TestComponentLifeCycle()
{
ProcessManager& pm = ProcessManager::GetInstance();

// testing creation update destroy
GameObjectWeak test = GameObject::Create( "Test" );
Weak_ptr<TestComponent> comp = test.Lock()->AddComponent<TestComponent>();
pm.ProcessUpdate();

assert( callsCreate == 1 );
assert( callsEnable == 1 );
assert( callsStart == 1 );
assert( callsUpdate == 1 );
assert( callsLate == 1 );
assert( callsDisable == 0 );
assert( callsDestroy == 0 );

pm.ProcessUpdate();
comp.Lock()->Destroy();
pm.ProcessUpdate();

assert( callsCreate == 1 );
assert( callsEnable == 1 );
assert( callsStart == 1 );
assert( callsUpdate == 2 );
assert( callsLate == 2 );
assert( callsDisable == 1 );
assert( callsDestroy == 1 );

ResetCounter();



// testing creation, disabling before first update, deletion while disabled
comp = test.Lock()->AddComponent<TestComponent>();
comp.Lock()->SetEnabled( false );

assert( callsCreate == 1 );
assert( callsEnable == 1 );
assert( callsStart == 0 );
assert( callsUpdate == 0 );
assert( callsLate == 0 );
assert( callsDisable == 1 );
assert( callsDestroy == 0 );

// no updating during disabled
pm.ProcessUpdate();

assert( callsCreate == 1 );
assert( callsEnable == 1 );
assert( callsStart == 0 );
assert( callsUpdate == 0 );
assert( callsLate == 0 );
assert( callsDisable == 1 );
assert( callsDestroy == 0 );

// updated reenabling
comp.Lock()->SetEnabled( true );
pm.ProcessUpdate();

assert( callsCreate == 1 );
assert( callsEnable == 2 );
assert( callsStart == 1 );
assert( callsUpdate == 1 );
assert( callsLate == 1 );
assert( callsDisable == 1 );
assert( callsDestroy == 0 );

pm.ProcessUpdate();

assert( callsCreate == 1 );
assert( callsEnable == 2 );
assert( callsStart == 1 );
assert( callsUpdate == 2 );
assert( callsLate == 2 );
assert( callsDisable == 1 );
assert( callsDestroy == 0 );


//destroy on disabled -> no call of onDisable
comp.Lock()->SetEnabled( false );
test.Lock()->Destroy();
pm.ProcessUpdate();


assert( callsCreate == 1 );
assert( callsEnable == 2 );
assert( callsStart == 1 );
assert( callsUpdate == 2 );
assert( callsLate == 2 );
assert( callsDisable == 2 );
assert( callsDestroy == 1 );


// test creation, instant disable, destroy
ResetCounter();
test = GameObject::Create( "Test" );
comp = test.Lock()->AddComponent<TestComponent>();
test.Lock()->SetComponentEnabled( false, TestComponent::COMPONENT_ID );
test.Lock()->Destroy();

assert( callsCreate == 1 );
assert( callsEnable == 1 );
assert( callsStart == 0 );
assert( callsUpdate == 0 );
assert( callsLate == 0 );
assert( callsDisable == 1 );
assert( callsDestroy == 1 );

pm.Release();

std::cout << "Test Component Life Cycle: OK" << std::endl;

}

class TestStarter
{
public:
	TestStarter( void (*Functor)(void) )
	{
		Functor();
	}
};

#ifdef RUN_TESTING
TestStarter start( TestComponentLifeCycle );
#endif
